﻿namespace SmsServerClient
{
    using System;
    using System.IO;
    using System.Net;
    using System.Net.Sockets;
    using System.Runtime.CompilerServices;
    using System.Text;
    using System.Threading;
    using MSRI.HelperClasses;

    public class TcpSocketClass
    {
        private byte[] Data;
        public int IsConnected;
        private Socket m_mainSocket;
        private int Offset;
        public AsyncCallback pfnWorkerCallBack;
        public int PortInUse;
        private Socket WorkerSocket;

        public event CommandReceivedDelegate CommandReceived;

        public event ConnectedDelegate Connected;

        public event DeliveryReportReceivedDelegate DeliveryReportReceived;

        public event DisconnectedDelegate Disconnected;

        public event MessageReceivedDelegate MessageReceived;

        public event SmsReceivedDelegate SmsReceived;

        public TcpSocketClass(IPAddress ip ,short port)
        {
            try
            {
                this.m_mainSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                IPEndPoint localEP = new IPEndPoint(ip, port);
                this.m_mainSocket.Bind(localEP);
                this.m_mainSocket.Listen(1);
                this.WorkerSocket = null;
                this.Data = new byte[0x1000];
                Interlocked.Exchange(ref this.IsConnected, 0);
                Interlocked.Exchange(ref this.Offset, 0);
                this.PortInUse = port;
            }
            catch (Exception exception)
            {
                this.m_mainSocket = null;
                this.PortInUse = -1;
            }
        }

        internal void Disconnect(bool p)
        {
            if (this.WorkerSocket != null)
            {
                this.WorkerSocket.Close();
                this.WorkerSocket = null;
                this.pfnWorkerCallBack = null;
            }
            Interlocked.Exchange(ref this.IsConnected, 0);
            if (this.Disconnected != null)
            {
                this.Disconnected(p);
            }
        }

        public void OnClientConnect(IAsyncResult asyn)
        {
            try
            {
                this.WorkerSocket = this.m_mainSocket.EndAccept(asyn);
                Interlocked.Exchange(ref this.Offset, 0);
                Interlocked.Exchange(ref this.IsConnected, 1);
                this.WaitForData(this.WorkerSocket);
                if (this.Connected != null)
                {
                    this.Connected();
                }
            }
            catch (Exception exception)
            {
                Interlocked.Exchange(ref this.IsConnected, 0);
            }
        }

        public void OnDataReceived(IAsyncResult asyn)
        {
            if ((this.WorkerSocket != null) && this.WorkerSocket.Connected)
            {
                try
                {
                    int num = this.WorkerSocket.EndReceive(asyn);
                    byte num2 = Convert.ToByte(Delim.Packet);
                    char ch = Convert.ToChar(Delim.Field);
                    for (int i = 0; i < num; i++)
                    {
                        int num5;
                        if (this.Data[this.Offset] != num2)
                        {
                            goto Label_01DE;
                        }
                        char[] chars = new char[this.Offset];
                        Encoding.UTF8.GetDecoder().GetChars(this.Data, 0, this.Offset, chars, 0);
                        string message = new string(chars);
                        string[] fields = message.Split(new char[] { ch });
                        try
                        {
                            if (int.Parse(fields[fields.Length - 1]) == (message.Length - fields[fields.Length - 1].Length))
                            {
                                MessageTypeEnum unKnown;
                                try
                                {
                                    if (fields.Length > 2)
                                    {
                                        unKnown = (MessageTypeEnum) int.Parse(fields[0]);
                                    }
                                    else
                                    {
                                        unKnown = MessageTypeEnum.UnKnown;
                                    }
                                }
                                catch (Exception exception)
                                {
                                    unKnown = MessageTypeEnum.UnKnown;
                                }
                                switch (unKnown)
                                {
                                    case MessageTypeEnum.Sms:
                                        if (this.SmsReceived != null)
                                        {
                                            this.SmsReceived(new SmsClass(fields));
                                        }
                                        goto Label_01A2;

                                    case MessageTypeEnum.Command:
                                        if (this.CommandReceived != null)
                                        {
                                            this.CommandReceived(new CommandClass(fields));
                                        }
                                        goto Label_01A2;

                                    case MessageTypeEnum.DeliveryReport:
                                        if (this.DeliveryReportReceived != null)
                                        {
                                            this.DeliveryReportReceived(new DeliveryReportClass(fields));
                                        }
                                        goto Label_01A2;
                                }
                                if (this.MessageReceived != null)
                                {
                                    this.MessageReceived(message);
                                }
                            }
                        }
                        catch (Exception exception2)
                        {
                        }
                    Label_01A2:
                        num5 = 1;
                        while (num5 < (num - i))
                        {
                            this.Data[num5 - 1] = this.Data[this.Offset + num5];
                            num5++;
                        }
                        Interlocked.Exchange(ref this.Offset, 0);
                        continue;
                    Label_01DE:
                        Interlocked.Increment(ref this.Offset);
                    }
                    this.WaitForData(this.WorkerSocket);
                }
                catch (Exception exception3)
                {
                    this.Disconnect(true);
                }
            }
        }

        public bool SendData(byte[] data, int size)
        {
            try
            {
                if (((this.IsConnected == 1) && (this.WorkerSocket != null)) && this.WorkerSocket.Connected)
                {
                    this.WorkerSocket.Send(data, size, SocketFlags.None);
                }
            }
            catch (Exception exception)
            {
                this.Disconnect(true);
            }
            if (this.IsConnected != 1)
            {
                return false;
            }
            return true;
        }

        public void SendMessage(string Msg)
        {
            if ((this.WorkerSocket != null) && this.WorkerSocket.Connected)
            {
                try
                {
                    NetworkStream stream = new NetworkStream(this.WorkerSocket);
                    StreamWriter writer = new StreamWriter(stream);
                    object obj2 = Msg;
                    object[] objArray = new object[] { obj2, Convert.ToChar(Delim.Field), (Msg.Length + 1).ToString(), Convert.ToChar(Delim.Packet) };
                    Msg = string.Concat(objArray);
                    writer.Write(Msg);
                    writer.Flush();
                }
                catch (Exception exception)
                {
                    this.Disconnect(true);
                }
            }
        }

        public bool StartListener()
        {
            try
            {
                if (this.m_mainSocket == null)
                {
                    throw new Exception("Listener Socket null....");
                }
                if (this.WorkerSocket != null)
                {
                    throw new Exception("Worker socket not null..");
                }
                this.m_mainSocket.BeginAccept(new AsyncCallback(this.OnClientConnect), null);
                return true;
            }
            catch (Exception exception)
            {
                return false;
            }
        }

        public void WaitForData(Socket soc)
        {
            if ((soc != null) && soc.Connected)
            {
                try
                {
                    if (this.pfnWorkerCallBack == null)
                    {
                        this.pfnWorkerCallBack = new AsyncCallback(this.OnDataReceived);
                    }
                    soc.BeginReceive(this.Data, this.Offset, 0x1000 - this.Offset, SocketFlags.None, this.pfnWorkerCallBack, null);
                }
                catch (Exception exception)
                {
                    this.Disconnect(true);
                }
            }
        }

        public delegate void CommandReceivedDelegate(CommandClass Command);

        public delegate void ConnectedDelegate();

        public delegate void DeliveryReportReceivedDelegate(DeliveryReportClass Command);

        public delegate void DisconnectedDelegate(bool ShouldRestart);

        public delegate void MessageReceivedDelegate(string Message);

        public delegate void SmsReceivedDelegate(SmsClass Message);
    }
}

